#!/usr/bin/env python
# -*- coding:utf-8 -*-

# file:web_streamlit_test.py
# author:张世航
# datetime:2024/12/23 23:48
# software: PyCharm
"""
中国各省、直辖市、自治区、特别行政区的疫情数据CSV数据分析
"""
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

# 设置matplotlib字体为支持中文的字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False

# 1. 数据上传
st.title("新冠病毒感染数据分析应用")
st.write("请上传中国各省、直辖市、自治区、特别行政区的疫情数据（CSV格式）")

uploaded_file = st.file_uploader("选择CSV文件", type=["csv"])

if uploaded_file is not None:
    # 2. 数据预处理
    try:

        if not uploaded_file.name.endswith('.csv'):
            st.error("请上传CSV格式的文件。")
        else:
            data = pd.read_csv(uploaded_file, encoding='utf-8')

            # 检查数据格式,这里使用 all() 函数和一个生成器表达式来检查 required_columns 列表中的每个列名是否都存在于 data（一个 DataFrame 对象）的列中
            required_columns = ['dateId', 'confirmedIncr', 'provinceName']
            if not all(col in data.columns for col in required_columns):
                st.error("上传的文件格式不正确，请确保包含以下列: " + ", ".join(required_columns))
            else:
                # 清洗数据，删除包含缺失值的行，记住这个dropna()
                data.dropna(inplace=True)

                # 将 dateId 列从 YYYYMMDD 格式转换为日期格式,astype(str) 确保列中的值被当作字符串处理，format='%Y%m%d' 指定了日期字符串的格式，errors='coerce' 会将任何不符合格式的值转换为 NaT（Not a Time，Pandas 中的缺失日期时间值）
                #反复学习！
                data['dateId'] = pd.to_datetime(data['dateId'].astype(str), format='%Y%m%d', errors='coerce')
                data.dropna(subset=['dateId'], inplace=True)  # 在转换日期格式后，这行代码再次使用 dropna() 方法移除 data DataFrame 中 dateId 列现在包含的任何缺失值（NaT）

                data.sort_values('dateId', inplace=True)

                # 3. 用户选择时间范围
                st.subheader("选择时间范围")
                min_date = data['dateId'].min()  # 获取最小日期
                max_date = data['dateId'].max()  # 获取最大日期
                start_date = st.date_input("开始日期", value=min_date)
                end_date = st.date_input("结束日期", value=max_date)

                # 根据选择的时间范围过滤数据
                filtered_data = data[
                    (data['dateId'] >= pd.to_datetime(start_date)) & (data['dateId'] <= pd.to_datetime(end_date))]

                # 4. 数据分析
                total_trend = filtered_data.groupby('dateId')['confirmedIncr'].sum().reset_index()

                # 5. 风险区域识别
                #滑块控件的运用
                threshold = st.slider("选择感染人数阈值", 0, 10000, 1000)
                high_risk = filtered_data[filtered_data['confirmedIncr'] > threshold].reset_index(drop=True)#索引重置

                # 6. 图表展示
                st.subheader("总感染趋势图")
                plt.figure(figsize=(10, 5))
                plt.plot(total_trend['dateId'], total_trend['confirmedIncr'], label='总新增确诊', color='blue')
                plt.title("新冠病毒感染趋势")
                plt.xlabel("日期")
                plt.ylabel("新增确诊人数")
                plt.xticks(rotation=45)  # 旋转x轴标签以便更好地显示
                plt.legend()             #显示图例，其实是标签
                st.pyplot(plt)           #使用 Streamlit 的 st.pyplot 函数将 Matplotlib 图表渲染到 Streamlit 应用中。

                # 各省感染曲线图
                st.subheader("各省感染曲线图")
                provinces = filtered_data['provinceName'].unique()
                selected_province = st.selectbox("选择省份", provinces)
                province_data = filtered_data[filtered_data['provinceName'] == selected_province]

                plt.figure(figsize=(10, 5))
                plt.plot(province_data['dateId'], province_data['confirmedIncr'], label=selected_province,
                         color='orange')
                plt.title(f"{selected_province} 新冠病毒感染趋势")
                plt.xlabel("日期")
                plt.ylabel("新增确诊人数")
                plt.xticks(rotation=45)
                plt.legend()
                st.pyplot(plt)

                # 7. 高风险区域图
                st.subheader("高风险区域")
                if not high_risk.empty:
                    st.write("以下省份的新增确诊人数超过阈值：")
                    st.write(high_risk[['provinceName', 'dateId', 'confirmedIncr']])

                    # 绘制高风险区域图
                    plt.figure(figsize=(10, 5))
                    for province in high_risk['provinceName'].unique():
                        province_high_risk_data = high_risk[high_risk['provinceName'] == province]
                        #high_risk[high_risk['provinceName'] == province] 会根据 province 的值动态返回不同的行(即内部的布尔series)，而不是固定的 high_risk[0] 或 high_risk[1]。每次循环迭代时，province 的值都会改变，所以这个表达式会返回与当前迭代的省份名称相匹配的行。
                        plt.plot(province_high_risk_data['dateId'], province_high_risk_data['confirmedIncr'],
                                 label=province)  # 添加省份线条
                    plt.title("高风险区域新增确诊人数")
                    plt.xlabel("日期")
                    plt.ylabel("新增确诊人数")
                    plt.axhline(y=threshold, color='red', linestyle='--', label='阈值')  # 添加阈值线
                    plt.xticks(rotation=45)  
                    plt.legend(title="省份", loc='upper right')
                    st.pyplot(plt)
                else:
                    st.write("没有省份的新增确诊人数超过阈值。")

                # 8. 结果输出
                st.download_button("下载分析结果", filtered_data.to_csv(index=False).encode('utf-8'),
                                   "analysis_results.csv", "text/csv")

    except Exception as e:
        st.error(f"发生错误: {e}")
